namespace org.apache.velocity.runtime.resource.loader
{
	/*
	* The Apache Software License, Version 1.1
	*
	* Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
	* reserved.
	*
	* Redistribution and use in source and binary forms, with or without
	* modification, are permitted provided that the following conditions
	* are met:
	*
	* 1. Redistributions of source code must retain the above copyright
	*    notice, this list of conditions and the following disclaimer.
	*
	* 2. Redistributions in binary form must reproduce the above copyright
	*    notice, this list of conditions and the following disclaimer in
	*    the documentation and/or other materials provided with the
	*    distribution.
	*
	* 3. The end-user documentation included with the redistribution, if
	*    any, must include the following acknowlegement:
	*       "This product includes software developed by the
	*        Apache Software Foundation (http://www.apache.org/)."
	*    Alternately, this acknowlegement may appear in the software itself,
	*    if and wherever such third-party acknowlegements normally appear.
	*
	* 4. The names "The Jakarta Project", "Velocity", and "Apache Software
	*    Foundation" must not be used to endorse or promote products derived
	*    from this software without prior written permission. For written
	*    permission, please contact apache@apache.org.
	*
	* 5. Products derived from this software may not be called "Apache"
	*    nor may "Apache" appear in their names without prior written
	*    permission of the Apache Group.
	*
	* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
	* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
	* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
	* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
	* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
	* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
	* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
	* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
	* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
	* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
	* SUCH DAMAGE.
	* ====================================================================
	*
	* This software consists of voluntary contributions made by many
	* individuals on behalf of the Apache Software Foundation.  For more
	* information on the Apache Software Foundation, please see
	* <http://www.apache.org/>.
	*/
	using System;
	using Resource = org.apache.velocity.runtime.resource.Resource;
	using ResourceNotFoundException = org.apache.velocity.exception.ResourceNotFoundException;
	
	/// <summary> This is a simple template file loader that loads templates
	/// from a DataSource instead of plain files.
	/// *
	/// It can be configured with a datasource name, a table name,
	/// id column (name), content column (the template body) and a
	/// datetime column (for last modification info).
	/// <br>
	/// <br>
	/// Example configuration snippet for velocity.properties:
	/// <br>
	/// <br>
	/// resource.loader = file, ds <br>
	/// <br>
	/// ds.resource.loader.public.name = DataSource <br>
	/// ds.resource.loader.description = Velocity DataSource Resource Loader <br>
	/// ds.resource.loader.class = org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader <br>
	/// ds.resource.loader.resource.datasource = java:comp/env/jdbc/Velocity <br>
	/// ds.resource.loader.resource.table = tb_velocity_template <br>
	/// ds.resource.loader.resource.keycolumn = id_template <br>
	/// ds.resource.loader.resource.templatecolumn = template_definition <br>
	/// ds.resource.loader.resource.timestampcolumn = template_timestamp <br>
	/// ds.resource.loader.cache = false <br>
	/// ds.resource.loader.modificationCheckInterval = 60 <br>
	/// <br>
	/// Example WEB-INF/web.xml: <br>
	/// <br>
	/// <resource-ref> <br>
	/// <description>Velocity template DataSource</description> <br>
	/// <res-ref-name>jdbc/Velocity</res-ref-name> <br>
	/// <res-type>javax.sql.DataSource</res-type> <br>
	/// <res-auth>Container</res-auth> <br>
	/// </resource-ref> <br>
	/// <br>
	/// <br>
	/// and Tomcat 4 server.xml file: <br>
	/// [...] <br>
	/// <Context path="/exampleVelocity" docBase="exampleVelocity" debug="0"> <br>
	/// [...] <br>
	/// <ResourceParams name="jdbc/Velocity"> <br>
	/// <parameter> <br>
	/// <name>driverClassName</name> <br>
	/// <value>org.hsql.jdbcDriver</value> <br>
	/// </parameter> <br>
	/// <parameter> <br>
	/// <name>driverName</name> <br>
	/// <value>jdbc:HypersonicSQL:database</value> <br>
	/// </parameter> <br>
	/// <parameter> <br>
	/// <name>user</name> <br>
	/// <value>database_username</value> <br>
	/// </parameter> <br>
	/// <parameter> <br>
	/// <name>password</name> <br>
	/// <value>database_password</value> <br>
	/// </parameter> <br>
	/// </ResourceParams> <br>
	/// [...] <br>
	/// </Context> <br>
	/// [...] <br>
	/// <br>
	/// Example sql script:<br>
	/// CREATE TABLE tb_velocity_template ( <br>
	/// id_template varchar (40) NOT NULL , <br>
	/// template_definition text (16) NOT NULL , <br>
	/// template_timestamp datetime NOT NULL  <br>
	/// ) <br>
	/// *
	/// </summary>
	/// <author> <a href="mailto:david.kinnvall@alertir.com">David Kinnvall</a>
	/// </author>
	/// <author> <a href="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
	/// </author>
	/// <author> <a href="mailto:lachiewicz@plusnet.pl">Sylwester Lachiewicz</a>
	/// </author>
	/// <version> $Id: DataSourceResourceLoader.cs,v 1.1 2002/07/29 14:34:03 corts Exp $
	/// 
	/// </version>
	public class DataSourceResourceLoader:ResourceLoader
	{
		private System.String dataSourceName;
		private System.String tableName;
		private System.String keyColumn;
		private System.String templateColumn;
		private System.String timestampColumn;
		private InitialContext ctx;
		private DataSource dataSource;
		
		public virtual void  init(ExtendedProperties configuration)
		{
			dataSourceName = configuration.getString("resource.datasource");
			tableName = configuration.getString("resource.table");
			keyColumn = configuration.getString("resource.keycolumn");
			templateColumn = configuration.getString("resource.templatecolumn");
			timestampColumn = configuration.getString("resource.timestampcolumn");
			
			System.Diagnostics.Process.info("Resources Loaded From: " + dataSourceName + "/" + tableName);
			System.Diagnostics.Process.info("Resource Loader using columns: " + keyColumn + ", " + templateColumn + " and " + timestampColumn);
			System.Diagnostics.Process.info("Resource Loader Initalized.");
		}
		
		public override bool isSourceModified(Resource resource)
		{
			return (resource.LastModified != readLastModified(resource, "checking timestamp"));
		}
		
		public override long getLastModified(Resource resource)
		{
			return readLastModified(resource, "getting timestamp");
		}
		
		/// <summary> Get an InputStream so that the Runtime can build a
		/// template with it.
		/// *
		/// </summary>
		/// <param name="name">name of template
		/// </param>
		/// <returns>InputStream containing template
		/// 
		/// </returns>
		//UPGRADE_NOTE: Synchronized keyword was removed from method 'getResourceStream'. Lock expression was added. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1027"'
		public override System.IO.Stream getResourceStream(System.String name)
		{
			lock(this)
			{
				if (name == null || name.Length == 0)
				{
					throw new ResourceNotFoundException("Need to specify a template name!");
				}
				
				try
				{
					System.Data.OleDb.OleDbConnection conn = openDbConnection();
					
					try
					{
						//UPGRADE_TODO: The equivalent of java.sql.ResultSet must call Close() before performing any other operation with the associated connection. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1129"'
						System.Data.OleDb.OleDbDataReader rs = readData(conn, templateColumn, name);
						
						try
						{
							if (rs.Read())
							{
								//UPGRADE_ISSUE: Method 'java.sql.ResultSet.getAsciiStream' was not converted. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1000_javasqlResultSetgetAsciiStream_javalangString"'
								return new System.IO.BufferedStream(rs.getAsciiStream(templateColumn));
							}
							else
							{
								System.String msg = "DataSourceResourceLoader Error: cannot find resource " + name;
								System.Diagnostics.Process.error(msg);
								
								throw new ResourceNotFoundException(msg);
							}
						}
						finally
						{
							rs.Close();
						}
					}
					finally
					{
						closeDbConnection(conn);
					}
				}
				catch (System.Exception e)
				{
					System.String msg = "DataSourceResourceLoader Error: database problem trying to load resource " + name + ": " + e.ToString();
					
					System.Diagnostics.Process.error(msg);
					
					throw new ResourceNotFoundException(msg);
					
				}
				
			}
		}
		
		/// <summary>  Fetches the last modification time of the resource
		/// *
		/// </summary>
		/// <param name="resource">Resource object we are finding timestamp of
		/// </param>
		/// <param name="i_operation">string for logging, indicating caller's intention
		/// *
		/// </param>
		/// <returns>timestamp as long
		/// 
		/// </returns>
		private long readLastModified(Resource resource, System.String i_operation)
		{
			/*
			*  get the template name from the resource
			*/
			
			System.String name = resource.Name;
			try
			{
				System.Data.OleDb.OleDbConnection conn = openDbConnection();
				
				try
				{
					//UPGRADE_TODO: The equivalent of java.sql.ResultSet must call Close() before performing any other operation with the associated connection. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1129"'
					System.Data.OleDb.OleDbDataReader rs = readData(conn, timestampColumn, name);
					try
					{
						if (rs.Read())
						{
							return (System.Convert.ToDateTime(rs[(timestampColumn)]).Ticks - 621355968000000000) / 10000;
						}
						else
						{
							System.Diagnostics.Process.error("DataSourceResourceLoader Error: while " + i_operation + " could not find resource " + name);
						}
					}
					finally
					{
						rs.Close();
					}
				}
				finally
				{
					closeDbConnection(conn);
				}
			}
			catch (System.Exception e)
			{
				System.Diagnostics.Process.error("DataSourceResourceLoader Error: error while " + i_operation + " when trying to load resource " + name + ": " + e.ToString());
			}
			return 0;
		}
		
		/// <summary>   gets connection to the datasource specified through the configuration
		/// parameters.
		/// *
		/// </summary>
		/// <returns>connection
		/// 
		/// </returns>
		private System.Data.OleDb.OleDbConnection openDbConnection()
		{
			if (ctx == null)
			{
				ctx = new InitialContext();
			}
			
			if (dataSource == null)
			{
				dataSource = (DataSource) ctx.lookup(dataSourceName);
			}
			
			return dataSource.Connection;
		}
		
		/// <summary>  Closes connection to the datasource
		/// </summary>
		private void  closeDbConnection(System.Data.OleDb.OleDbConnection conn)
		{
			try
			{
				conn.Close();
			}
			catch (System.Exception e)
			{
				System.Diagnostics.Process.info("DataSourceResourceLoader Quirk: problem when closing connection: " + e.ToString());
			}
		}
		
		/// <summary>  Reads the data from the datasource.  It simply does the following query :
		/// <br>
		/// SELECT <i>columnNames</i> FROM <i>tableName</i> WHERE <i>keyColumn</i>
		/// = '<i>templateName</i>'
		/// <br>
		/// where <i>keyColumn</i> is a class member set in init()
		/// *
		/// </summary>
		/// <param name="conn">connection to datasource
		/// </param>
		/// <param name="columnNames">columns to fetch from datasource
		/// </param>
		/// <param name="templateName">name of template to fetch
		/// </param>
		/// <returns>result set from query
		/// 
		/// </returns>
		//UPGRADE_TODO: The equivalent of java.sql.ResultSet must call Close() before performing any other operation with the associated connection. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1129"'
		private System.Data.OleDb.OleDbDataReader readData(System.Data.OleDb.OleDbConnection conn, System.String columnNames, System.String templateName)
		{
			System.Data.OleDb.OleDbCommand stmt = SupportClass.TransactionManager.manager.CreateStatement(conn);
			
			System.String sql = "SELECT " + columnNames + " FROM " + tableName + " WHERE " + keyColumn + " = '" + templateName + "'";
			
			System.Data.OleDb.OleDbCommand temp_OleDbCommand;
			temp_OleDbCommand = stmt;
			temp_OleDbCommand.CommandText = sql;
			return temp_OleDbCommand.ExecuteReader();
		}
	}
}